// 
#pragma once
#ifndef __HWINCOMPONENT_H__
#define __HWINCOMPONENT_H__

#include "hwindef.h"
#include "hwinobject.h"



namespace harlinn
{
    namespace windows
    {
        using namespace boost::signals2;

        class Component;

        class Components : public Object 
        {
        public:
            typedef std::vector< std::shared_ptr<Component> > vector;
        private:
            friend class Component;
            Component*  owner;
            vector items;

            HWIN_EXPORT bool Add(std::shared_ptr<Component> theCompnent);
            HWIN_EXPORT bool Remove(std::shared_ptr<Component> theCompnent);
            HWIN_EXPORT bool Contains(std::shared_ptr<Component> theCompnent);
            HWIN_EXPORT void DeleteComponents( );
            HWIN_EXPORT void SetDestructionInProgress();
        public:
            HWIN_EXPORT explicit Components(Component* theOwner);
            HWIN_EXPORT ~Components( ); 

            typedef vector::reference reference;
            typedef vector::const_reference const_reference;
            typedef vector::value_type value_type;
            typedef vector::size_type size_type;
            typedef vector::const_iterator const_iterator;
            typedef vector::iterator iterator;


            size_type size() const 
            { 
                HWIN_TRACE();
                return items.size(); 
            }

            const_reference at(size_type position) const 
            { 
                HWIN_TRACE();
                return items.at(position); 
            }
            reference at(size_type position) 
            { 
                HWIN_TRACE();
                return items.at(position); 
            }

            const_reference operator[](size_type position) const 
            { 
                HWIN_TRACE();
                return items[position]; 
            }
            reference operator[](size_type position) 
            { 
                HWIN_TRACE();
                return items[position]; 
            }


            const_iterator begin() const 
            { 
                HWIN_TRACE();
                return items.begin(); 
            }
            iterator begin() 
            { 
                HWIN_TRACE();
                return items.begin(); 
            }

            const_iterator end() const 
            { 
                HWIN_TRACE();
                return items.end(); 
            }
            iterator end() 
            { 
                HWIN_TRACE();
                return items.end(); 
            }
        };


        enum class ComponentState : int
        {
            Constructing,
            Initializing,
            Initialized,
            Destructing
        };

        class Component : public Object
        {
            friend class Components;
            std::weak_ptr<Object> owner;
            std::shared_ptr<Components> components;
            ComponentState state;
        public:
            typedef Object Base;

            HWIN_EXPORT explicit Component( );
            HWIN_EXPORT ~Component( );

            ComponentState State() const 
            { 
                HWIN_TRACE();
                return state; 
            }

            HWIN_EXPORT Component& Initialize();
            HWIN_EXPORT Component& Initialize(std::shared_ptr<Component> theOwner);


            HWIN_EXPORT std::shared_ptr<const Components> GetComponents() const;
            HWIN_EXPORT std::shared_ptr<Components> GetComponents();

            HWIN_EXPORT bool IsOwnerOf(std::shared_ptr<const Component> theComponent, bool checkObjectHierarchy = true ) const;
            HWIN_EXPORT bool IsOwnerOf(const Component* theComponent, bool checkObjectHierarchy = true ) const;

            HWIN_EXPORT bool IsOwnedBy(std::shared_ptr<const Component> theComponent, bool checkObjectHierarchy = true ) const;
            HWIN_EXPORT bool IsOwnedBy(const Component* theComponent, bool checkObjectHierarchy = true ) const;

            HWIN_EXPORT virtual std::shared_ptr<Object> GetOwner() const;
            HWIN_EXPORT std::shared_ptr<Component> GetOwnerAsComponent() const;
            HWIN_EXPORT Component& SetOwner(std::shared_ptr<Component> theNewOwner);
            
            signal<void (Component* sender)> OnOwnerChanged;
            signal<void (Component* sender, Component* theComponent)> OnComponentAdded;
            signal<void (Component* sender, Component* theComponent)> OnComponentRemoved;

        protected:
            HWIN_EXPORT virtual void DoOnInitialize( );
            HWIN_EXPORT virtual void DoOnOwnerChanged( );
            HWIN_EXPORT virtual void DoOnComponentAdded(std::shared_ptr<Component> theComponent);
            HWIN_EXPORT virtual void DoOnComponentRemoved(std::shared_ptr<Component> theComponent);
        
            HWIN_EXPORT virtual void SetDestructionInProgress();


        };


        template< typename T >
        std::shared_ptr<T> make_component( )
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>();
            result->Initialize( );
            return result;
        }

        template< typename T >
        std::shared_ptr<T> make_component(std::shared_ptr<Component> theOwner)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>();
            result->Initialize( theOwner );
            return result;
        }

        template< typename T, typename A >
        std::shared_ptr<T> make_component(std::shared_ptr<Component> theOwner, const A& argument)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument);
            result->Initialize( theOwner );
            return result;
        }

        template< typename T, typename A1, typename A2 >
        std::shared_ptr<T> make_component(std::shared_ptr<Component> theOwner, const A1& argument1, const A2& argument2)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument1,argument2);
            result->Initialize( theOwner );
            return result;
        }

        template< typename T, typename A1, typename A2, typename A3 >
        std::shared_ptr<T> make_component(std::shared_ptr<Component> theOwner, const A1& argument1, const A2& argument2, const A3& argument3)
        {
            HWIN_TRACE();
            auto result = std::make_shared<T>(argument1,argument2,argument3);
            result->Initialize( theOwner );
            return result;
        }



    };
};


#endif //__HWINCOMPONENT_H__